import Participant from "./Participant";
import TrackBuilder from "./TrackBuilder";
import Message from "./Message";
import { TimeOutError } from "./error";

/**
 * jitsiConference的增强代理
 * 新增：维持唯一数组participants
 * 新增：维持唯一数组messages
 * 新增/增强：部分方法
 */
export default class {
    _joinResolve
    _joinReject

    _sendTextMessageResolve
    _sendTextMessageReject

    _delegate
    _participants = []

    _messages = []


    /**
     * @param delegate :JitsiConference
     */
    constructor(delegate) {
        this._delegate = delegate

        //监听本地用户加入，自动为本地用户创建Participant并加入到participants数组
        this.addEventListener(JitsiMeetJS.events.conference.CONFERENCE_JOINED,
            async () => {
                const participant = new Participant(this.myUserId())
                participant.select()
                participant.isLocal = true
                this.addParticipant(
                    participant
                );
                this._joinResolve()
                console.log('you joined')
            });

        //监听本地用户挂断
        this.addEventListener(
            JitsiMeetJS.events.conference.CONFERENCE_LEFT,
            () => {
                console.log('you left')
            }
        );

        //监听远程用户加入，自动为远程用户创建Participant并加入到participants数组
        this.addEventListener(
            JitsiMeetJS.events.conference.USER_JOINED,
            (id, user) => {
                const participant = new Participant(id)
                // console.log(user)
                if (user._displayName) {
                    participant.setName(user._displayName)
                }
                this.addParticipant(
                    participant
                )
                console.log(`user joined:${id}`);
            }
        );

        //监听远程用户挂断，自动从本地participants中移除
        this.addEventListener(
            JitsiMeetJS.events.conference.USER_LEFT,
            (id, user) => {
                console.log(`user left:${id}`);
                this.removeParticipant(id)
            }
        );

        //监听轨道加入（本地/远程），自动关联到相关用户Participant
        this.addEventListener(
            JitsiMeetJS.events.conference.TRACK_ADDED,
            (track) => {
                const participant = this.getParticipantByTrack(track);
                if (!participant) return
                participant.addTrack(track)
                console.log(`${participant.id}:${track.getType()} track added`);
                console.log(`muted:${track.isMuted()}`);
            }
        );

        //监听轨道移除（本地/远程），自动从相关用户Participant移除
        this.addEventListener(
            JitsiMeetJS.events.conference.TRACK_REMOVED,
            (track) => {
                const participant = this.getParticipantByTrack(track);
                if (!participant) return
                participant.removeTrack(track.getType())
                console.log(`${participant.id}:${track.getType()} track removed`);
            }
        );

        //role change
        this.addEventListener(
            JitsiMeetJS.events.conference.USER_ROLE_CHANGED,
            (id, role) => {
                const participant = this.getParticipant(id);
                if (!participant) return
                participant.role = role;
            }
        );

        //监听消息接受，并展示
        this.addEventListener(
            JitsiMeetJS.events.conference.MESSAGE_RECEIVED,
            (id, text, ts) => {
                const participant = this.getParticipant(id)
                if (!participant) return

                this.addMessage(new Message(participant, text))
                if (id == this.myUserId()) {
                    this._sendTextMessageResolve()
                }
            }
        );
        //监听用户改名，并自动设置到关联的Participant
        this.addEventListener(
            JitsiMeetJS.events.conference.DISPLAY_NAME_CHANGED,
            (id, name) => {
                this.getParticipant(id).setName(name)
                console.log(`${id}:'name changed:'${name}`)
            }
        );
    }

    /**
     * 增强：
     * 加入会议并返回promise
     * 若加入成功，将会添加并默认高亮本地用户到本Conference
     */
    join(password) {
        const promise = new Promise((resolve, reject) => {
            this._joinResolve = resolve
            this._joinReject = reject
        });
        this._delegate.join(password)
        return promise
    }

    /**
     * 原装：
     * 离开会议
     */
    leave() {
        this.clearParticipants()
        return this._delegate.leave()
    }

    /**
     * 原装：
     * 获取加入到本会议中的本地轨道
     */
    getLocalTracks() {
        return this._delegate.getLocalTracks()
    }

    /**
     * 新增：
     * 获取指定类型的本地轨道
     */
    getLocalTrack(type) {
        const track = this.getLocalTracks().filter(
            track => track.getType() == type
        )[0]
        return track || null
    }

    /**
     * 原装：
     * 添加指定轨道
     * 若添加成功，会自动关联到相关Participant
     */
    addTrack(track) {
        return this._delegate.addTrack(track)
    }

    /**
     * 新增：
     * 获取并添加指定类型的本地轨道到本会议
     * 若添加成功，会自动关联到本地Participant
     * @param {String} type :[video|desktop|audio]
     * throw UnknownTrackTypeError if specified type can not be recognized
     * throw GetLocalTrackFailedError if get track failed
     */
    async addLocalTrack(type) {
        const track = await TrackBuilder.getLocalTrack(type)
        await this.addTrack(track)
    }

    /**
     * 原装：
     * 将指定轨道从本会议中移除
     * 若移除成功，会自动从相关Participant移除轨道
     */
    removeTrack(track) {
        return this._delegate.removeTrack(track)
    }

    /**
     * 新增：
     * 将指定类型的本地轨道从本会议中移除
     * 若移除成功，会自动从本地Participant移除轨道
     */
    async removeLocalTrack(type) {
        const track = this.getLocalTrack(type)
        if (track) {
            await this.removeTrack(track)
            track.dispose()
        }
    }

    /**
     * 原装：
     * 添加指令监听器
     */
    addCommandListener(command, handler) {
        this._delegate.addCommandListener(command, handler)
    }

    /**
     * 原装：
     * 添加事件监听器
     */
    addEventListener(event, listener) {
        this._delegate.addEventListener(event, listener)
    }

    /**
     * 增强：
     * 替换了非主持人角色名（none -> participant）
     * 以此来和jitsiParticipant保持一致
     */
    getRole() {
        let role = this._delegate.getRole()
        return role == 'none' ? 'participant' : role
    }

    /**
     * 原装：
     * 获取本地userId
     */
    myUserId() {
        return this._delegate.myUserId()
    }

    /**
    * 原装：
    */
    isStartAudioMuted() {
        return this._delegate.isStartAudioMuted()
    }

    /**
     * 增强：
     * 设置本地展示用name（本地以及远程）
     */
    setDisplayName(name) {
        this.setLocalDisplayName(name)
        this._delegate.setDisplayName(name)
    }

    /**
     * 新增：
     * 设置本地展示用name（仅本地可见）
     */
    setLocalDisplayName(name) {
        this.getLocalParticipant().setName(name)
    }


    /**
     * 新增：
     * 获取本Conference所维持的participant数组（本地）
     */
    getParticipants() {
        return this._participants
    }

    /**
     * 新增：
     * 以id获取Participant
     */
    getParticipant(id) {
        return this._participants.find(v => {
            return v.id === id;
        });
    }

    /**
     * 新增：
     * 以轨道（track）获取Participant
     */
    getParticipantByTrack(track) {
        const participantId = track.getParticipantId()
        if (participantId == undefined || participantId == this.myUserId()) {
            return this.getLocalParticipant()
        } else {
            return this.getParticipant(participantId)
        }
    }

    /**
     * 新增：
     * 获取本地被被高亮的Participant
     */
    getSelectedParticipant() {
        return this._participants.find(v => {
            return v.selected === true
        })
    }

    /**
     * 新增：
     * 获取本地Participant
     */
    getLocalParticipant() {
        return this.getParticipant(this.myUserId())
    }

    /**
     * 新增：
     * 以id移除Participant（本地）
     */
    removeParticipant(id) {
        const index = this._participants.findIndex(v => {
            return v.id === id;
        })
        if (index == -1) return
        this._participants.splice(index, 1)
    }

    /**
     * 新增：
     * 添加Participant（本地）
     */
    addParticipant(participant) {
        this._participants.push(participant)
    }

    /**
     * 新增：
     * 高亮指定id的Participant
     */
    selectParticipant(id) {
        this._participants.forEach(v => {
            v.selected = false
        })
        this.getParticipant(id).selected = true
        this._delegate.selectParticipant(id)
    }

    /**
     * 新增：
     * 清空本地participants
     */
    clearParticipants() {
        this._participants = []
    }

    /**
     * 增强：
     * 发送消息到远程，返回Promise
     * 若7秒内未响应：Promise->reject
     */
    sendTextMessage(text) {
        const promise = new Promise((resolve, reject) => {
            this._sendTextMessageResolve = resolve
            this._sendTextMessageReject = reject
            
        });
        setTimeout(
            () => { this._sendTextMessageReject(new TimeOutError()) },
            7000
        )
        this._delegate.sendTextMessage(text)
        return promise
    }
    /**
     * 新增：
     * 获取本Conference所维持的message数组（本地）
     */
    getMessages() {
        return this._messages
    }

    /**
     * 新增：
     * 添加一条消息到本地messages
     */
    addMessage(m) {
        this._messages.push(m)
    }
}





